//
//  HESpeechListener.m
//  HealthFamily
//
//  Created by 吴欧 on 2020/11/24.
//  Copyright © 2020 honglutec. All rights reserved.
//

#import "HESpeechListener.h"

@interface HESpeechListener ()

@property(nonatomic,copy) NSString *currentText;

@property(nonatomic,assign)NSTimeInterval beginListenLocation;

@property (nonatomic, strong) AVAudioEngine *audioEngine;

@end

@implementation HESpeechListener


#pragma mark - LifeCycle
+(instancetype)sharedManager {
    static dispatch_once_t onceToken;
    static HESpeechListener *instance;
    dispatch_once(&onceToken, ^{
        instance = [[HESpeechListener alloc] init];
    });
    return instance;
}


-(instancetype)init
{
    self = [super init];
    if (self) {
        if (@available(iOS 10.0, *)) {
            self.listener = [[SFSpeechRecognizer alloc] initWithLocale:[NSLocale localeWithLocaleIdentifier:@"zh-CN"]];
        } else {
            // Fallback on earlier versions
        }
        [self.listener setDelegate:self];
        [self requestAuthorizationStatus];
    }
    return self;
}

-(void)requestAuthorizationStatus
{
    typeof(self) __weak weakself = self;
    if (@available(iOS 10.0, *)) {
        [SFSpeechRecognizer requestAuthorization:^(SFSpeechRecognizerAuthorizationStatus status) {
            typeof(weakself) __strong strongself = weakself;
            strongself.authorizationStatus = status;
        }];
    } else {
        // Fallback on earlier versions
    }
}

-(void)startRecognizer
{
    @try {
        // 取消上一个任务
        if (_recognitionTask) {
            [_recognitionTask cancel];
        }
        
        // 音视频场景配置，指定其他声音被强制变小
        AVAudioSession *audioSession = [AVAudioSession sharedInstance];
        if (@available(iOS 10.0, *)) {
            [audioSession setCategory:AVAudioSessionCategoryPlayAndRecord mode: AVAudioSessionModeMeasurement options: AVAudioSessionCategoryOptionDuckOthers error:nil];
        } else {
            // Fallback on earlier versions
        }
        [audioSession setActive:YES withOptions: AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil];
        
        _audioEngine = [[AVAudioEngine alloc] init];
        AVAudioInputNode *inputNode =  _audioEngine.inputNode;
     
        self.beginListenLocation = CFAbsoluteTimeGetCurrent();
        if (@available(iOS 10.0, *)) {
            self.recognitionRequest = [[SFSpeechAudioBufferRecognitionRequest alloc] init];
        } else {
            // Fallback on earlier versions
        }
        _recognitionRequest.shouldReportPartialResults = YES;
        self.inRecognizer = YES;

        typeof(self) __weak weakself = self;
        if (@available(iOS 10.0, *)) {
            self.recognitionTask = [self.listener recognitionTaskWithRequest:self.recognitionRequest resultHandler:^(SFSpeechRecognitionResult *result, NSError *error) {
                typeof(weakself) __strong strongself = weakself;
                if (strongself.inRecognizer) {
                    if (error != nil) {
                        [strongself endRecognizer];
                    }
                    else
                        if(result != nil) {
                            if (strongself.inRecognizer) {
                                strongself.currentText = [[result bestTranscription] formattedString];
                                
                                if (strongself.textBlock) {
                                    strongself.textBlock([[result bestTranscription] formattedString], strongself.inRecognizer);
                                }
                            }
                        }
                }
                
                if (error || [result isFinal]) {
                    //                if (inputNode) {
                    //                    [inputNode removeTapOnBus:0];
                    //                }
                    [strongself endRecognizer];
                }
            }];
        } else {
            // Fallback on earlier versions
        }
        
        // 配置麦克风输入。
        AVAudioFormat * recordingFormat = [inputNode outputFormatForBus:0];
        
        [inputNode installTapOnBus:0 bufferSize:1024 format:recordingFormat block:^(AVAudioPCMBuffer * _Nonnull buffer, AVAudioTime * _Nonnull when) {
            [self.recognitionRequest appendAudioPCMBuffer:buffer];
        }];
        [_audioEngine prepare];
        [_audioEngine startAndReturnError:nil];
    } @catch (NSException *exception) {
        DLog(@"录音错误")
    } @finally {
    }
    
}

-(void)endRecognizer
{
    self.inRecognizer = NO;
 
    if (self.textBlock) {
        self.textBlock(@"", self.inRecognizer);
    }
    
    // 当场景结束时，为了不影响其他场景播放声音变小，恢复声音；
    AVAudioSession *audioSession = [AVAudioSession sharedInstance];
    [audioSession setActive:NO withOptions: AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil];
    if (@available(iOS 10.0, *)) {
        [audioSession setCategory:AVAudioSessionCategoryPlayAndRecord mode: AVAudioSessionModeMeasurement options: AVAudioSessionCategoryOptionDefaultToSpeaker error:nil];
    } else {
        // Fallback on earlier versions
    }
    [audioSession setActive:YES withOptions: AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil];
    
    @try {
        if (self.audioEngine) {
            [self.audioEngine stop];
            self.audioEngine = nil;
        }
        if (self.recognitionRequest) {
            [self.recognitionRequest endAudio];
            self.recognitionRequest = nil;
        }
        if (self.recognitionTask) {
            [self.recognitionTask cancel];
            self.recognitionTask = nil;
        }
    } @catch (NSException *exception) {
        DLog(@"录音结束错误")
    } @finally {
    }
}

-(void)speechRecognizer:(SFSpeechRecognizer *)speechRecognizer availabilityDidChange:(BOOL)available
API_AVAILABLE(ios(10.0)){
    self.inRecognizer = !available;
}

-(void)giveBuffer:(CMSampleBufferRef)buffer
{
    if (self.recognitionRequest) {
        [self.recognitionRequest appendAudioSampleBuffer:buffer];
    }
    if (self.inRecognizer && (CFAbsoluteTimeGetCurrent() - self.beginListenLocation) > 30) {
        [self endRecognizer];
        [self startRecognizer];
    }
}

@end
